import numpy as np
import pymysql
import joblib
from utils import SQL, PropsSI, PhaseSI
from sympy import Symbol, solve

MAX_STAGE = 8
VERBOSE = False


class SuHeat:
    def __init__(self): 
        self.data = -np.ones((2, 5))  # 供热压力、温度、比焓、流量、位置
        
class SuWater:
    def __init__(self):
        self.data = -np.ones((5, 5))  # 补水压力、温度、比焓、流量、位置
        
class Stage:
    def __init__(self, turbine):
        self.data = -np.ones((MAX_STAGE, 5))
        self.EffStage = -np.ones(MAX_STAGE)
        self.turbine = turbine
        self.ebs = 0.001
        self.num_stages = 0
        
    def solve_stage(self):
        data = self.data
        EffStage = self.EffStage
        data[0, 2] = PropsSI("H", "P", data[0, 0], "T", data[0, 1], "Water")
        for i in range(1, data.shape[0]):
            ts = PropsSI("T",  "P", data[i, 0], "Q", 0, "Water")
#             print("当前温度", data[i, 1])
#             print("饱和温度", ts)
            if abs(data[i, 1] - ts) > 1:
                # 过热蒸汽
                data[i, 2] = PropsSI("H", "P", data[i, 0], "T", data[i, 1], "Water")
                s = PropsSI("S", "P", data[i - 1, 0], "H", data[i - 1, 2], "Water")
                data[i, 4] = PropsSI("H", "P", data[i, 0], "S", s, "Water")
                EffStage[i] = (data[i-1, 2] - data[i, 2])/(data[i-1, 2] - data[i, 4])
            else:
#                 print(i)
                if(EffStage[i] == -1):
                    EffStage[i] = 0.7
                else:
                    EffStage[i] += self.ebs 
                p = data[i-1, 0]
                h = data[i-1, 2]
                pp = data[i, 0]
                s = PropsSI("S", "P", data[i - 1, 0], "H", data[i - 1, 2], "Water")
                data[i, 4] = PropsSI("H", "P", data[i, 0], "S", s, "Water")
                # if i == 7:
                #     data[i, 4] = 2254026
                h_ = data[i, 4]
                data[i, 2] = data[i-1, 2] - (data[i-1, 2] - data[i, 4]) * EffStage[i]
        
    def get_curr_num_of_stage(self):
        for i in range(self.data.shape[0]):
            if self.data[i, 0] == -1 and self.data[i, 1] == -1:
                return i
        return 8
        
    def set_data(self):
        self.data[0, :4] = self.turbine.main[:4]
        reheat = self.turbine.reheat
        reheater_list = reheat.reheater_list
        for i in range(len(reheater_list)):
            pos = int(reheater_list[i].pos)
            self.data[pos, :2] = reheater_list[i].extraction[:2] 
        tmp = self.get_curr_num_of_stage()
        self.data[tmp, :4] = self.turbine.exhaust[:4]
        
    def get_data(self):
        self.turbine.main[:4] = self.data[0, :4]
        reheat = self.turbine.reheat
        reheater_list = reheat.reheater_list
        for i in range(len(reheater_list)):
            pos = int(reheater_list[i].pos)
            reheater_list[i].extraction[:3] = self.data[pos, :3]
        self.turbine.exhaust[:4] = self.data[self.get_curr_num_of_stage()-1, :4]
        
    def solve_step(self):
        self.solve_stage()
        self.get_data()
        for i in range(len(self.turbine.reheat.reheater_list)):
            self.turbine.reheat.reheater_list[i].solve()
        # 计算抽汽情况
        extraction = np.zeros(self.num_stages)
        for i in range(self.turbine.suheat.data.shape[0]):
            if self.turbine.suheat.data[i, -1] == -1:
                continue
            pos = int(self.turbine.suheat.data[i, 4])
            extraction[pos] -= self.turbine.suheat.data[i, 3]
            
        for i in range(len(self.turbine.reheat.reheater_list)):
            pos = int(self.turbine.reheat.reheater_list[i].pos)
            extraction[pos] -= self.turbine.reheat.reheater_list[i].extraction[3]            
        
        
        total_h = 0
        flow = self.data[0, 3]
        flows = np.zeros((MAX_STAGE))
        delta_s_hs = np.zeros((MAX_STAGE))
        for i in range(self.num_stages - 1):
            delta_s_h = self.data[i, 2] - self.data[i+1, 2]
            self.data[i, 3] = flow
            delta_s_hs[i] = delta_s_h
            flows[i] = flow / 3.6
            delta_h = flow * delta_s_h / 3.6
            # delta_hs.append(delta_h)
            flow += extraction[i+1]
            total_h += delta_h
        # delta_s_hs = np.array([221, 139, 108, 130,141,140,213, 0])
        total_h = np.sum(flows * delta_s_hs)
        return total_h
    
    def solve(self):
        self.num_stages = self.get_curr_num_of_stage()
        while(True):
            power_ = self.solve_step()
            delta = abs((power_ - self.turbine.power)/self.turbine.power)
            if delta < 0.01:
                break
            else:
                print(f'{power_}   {self.turbine.power}      {delta}')
                if delta > 0:
                    self.ebs = -0.01
                else:
                    self.ebs = 0.01
        
        
class Condensate:
    def __init__(self):
        self.condensate = -np.ones(3)
        self.circulating = -np.ones(2)
        self.cooling_water_t_rise = 0
        self.condensate_supercooling = 0
        self.cooling_terminal_difference = 0
        self.log_cooling_terminal_difference = 0
    

class Turbine:
    def __init__(self):
        self.sql = SQL()
        
        self.main = -np.ones(4)
        self.exhaust = -np.ones(4)
        self.feed = -np.ones(4)  # 锅炉给水
        self.eff = -np.ones(3)
        self.power = 0
        self.steam_rate = 0
        self.heat_rate = 0
        self.condensate = Condensate()
        self.stage = Stage(self)
        self.suheat = SuHeat()
        self.reheat = ReHeat(self)
        self.suwater = SuWater()

        
    def init_data(self):
        default_dict = joblib.load("2021-2-29.jl.z")
        self.sql.read_data(default_dict, 1)
        self.power = default_dict["电功率"]
        self.main = np.array([default_dict["主蒸汽压力"], default_dict["主蒸汽温度"], default_dict["主蒸汽比焓"], default_dict["主蒸汽流量"]])
        self.exhaust = np.array([default_dict["排气压力"], default_dict["排气温度"], default_dict["排气比焓"], default_dict["排气流量"]])
        self.condensate.circulating = np.array([default_dict["循环水进口温度"], default_dict["循环水出口温度"]]) 
        self.condensate.condensate = np.array([default_dict["凝结水温度"], default_dict["凝结水比焓"],  default_dict["凝结水流量"]]) 
        self.feed = np.array([default_dict["锅炉给水压力"], default_dict["锅炉给水温度"], default_dict["锅炉给水比焓"], default_dict["锅炉给水流量"]])
        self.reheat.high, self.reheat.isDeaecrator, self.reheat.low = default_dict["高加数目"], default_dict["有无除氧器"], default_dict["低加数目"] 
        self.reheat.create()



        # for i in range(0, 8):
        #     self.stage.data[i, 0] = default_dict[f"级末压力_{i+1}"]
        #     self.stage.data[i, 1] = default_dict[f"级末温度_{i+1}"]
        #     self.stage.data[i, 3] = default_dict[f"级内等效流量_{i+1}"]
        #     self.stage.data[i, 2] = default_dict[f"级末比焓_{i+1}"]
        #     self.stage.data[i, 4] = default_dict[f"级末理想比焓_{i+1}"] 
        #     self.stage.EffStage[i] = default_dict[f"级段效率_{i+1}"]

        for i in range(0, len(self.reheat.reheater_list)):
#             print(self.feed)

            self.reheat.reheater_list[i].pos = default_dict[f"加热器位置_{i+1}"]
            self.reheat.reheater_list[i].extraction[0] = default_dict[f"抽汽压力_{i+1}"]
            self.reheat.reheater_list[i].extraction[1] = default_dict[f"抽汽温度_{i+1}"]
            self.reheat.reheater_list[i].extraction[3] = default_dict[f"抽汽流量_{i+1}"]
            self.reheat.reheater_list[i].extraction[2] = default_dict[f"抽汽比焓_{i+1}"]

#             self.reheat.reheater_list[i].inlet[1] = default_dict[f"进口温度_{i+1}"]
#             self.reheat.reheater_list[i].inlet[3] = default_dict[f"进口流量_{i+1}"]
#             self.reheat.reheater_list[i].inlet[2] = default_dict[f"进口比焓_{i+1}"]
            if i != 0:
                self.reheat.reheater_list[i].outlet[1] = default_dict[f"出口温度_{i+1}"]
                self.reheat.reheater_list[i].outlet[3] = default_dict[f"出口流量_{i+1}"]
                self.reheat.reheater_list[i].outlet[2] = default_dict[f"出口比焓_{i+1}"]

            self.reheat.reheater_list[i].trap[1] = default_dict[f"疏水温度_{i+1}"]
            self.reheat.reheater_list[i].trap[3] = default_dict[f"疏水流量_{i+1}"]
            self.reheat.reheater_list[i].trap[2] = default_dict[f"疏水比焓_{i+1}"]


        for i in range(2):
            self.suheat.data[i, 0] = default_dict[f"供热抽汽压力_{i+1}"]
            self.suheat.data[i, 1] = default_dict[f"供热抽汽温度_{i+1}"]
            self.suheat.data[i, 3] = default_dict[f"供热抽汽流量_{i+1}"]
            self.suheat.data[i, 2] = default_dict[f"供热抽汽比焓_{i+1}"]
            self.suheat.data[i, 4] = default_dict[f"供热抽汽位置_{i+1}"]

        for i in range(5):
            self.suwater.data[i, 0] = default_dict[f"补水压力_{i+1}"]
            self.suwater.data[i, 1] = default_dict[f"补水温度_{i+1}"]
            self.suwater.data[i, 3] = default_dict[f"补水流量_{i+1}"]
            self.suwater.data[i, 2] = default_dict[f"补水比焓_{i+1}"]
            self.suwater.data[i, 4] = default_dict[f"补水位置_{i+1}"]
        
        self.reheat.set_diff()
        self.stage.set_data()
        
    def update_data(self):
        default_dict = joblib.load("2021-2-29.jl.z")
        for key in default_dict:
            default_dict[key] == -1
        
        self.reheat.get_diff()
        self.stage.get_data()
        default_dict["电功率"] = self.power
        default_dict["主蒸汽压力"], default_dict["主蒸汽温度"], default_dict["主蒸汽比焓"], default_dict["主蒸汽流量"] = self.main
        default_dict["排气压力"], default_dict["排气温度"], default_dict["排气比焓"], default_dict["排气流量"] = self.exhaust
        default_dict["循环水进口温度"], default_dict["循环水出口温度"] = self.condensate.circulating
        default_dict["凝结水温度"], default_dict["凝结水比焓"],  default_dict["凝结水流量"] = self.condensate.condensate
        default_dict["锅炉给水压力"], default_dict["锅炉给水温度"], default_dict["锅炉给水比焓"], default_dict["锅炉给水流量"] = self.feed
        default_dict["高加数目"], default_dict["有无除氧器"], default_dict["低加数目"] = self.reheat.high, self.reheat.isDeaecrator, self.reheat.low

        for i in range(0, 8):
            default_dict[f"级末压力_{i+1}"] = self.stage.data[i, 0]
            default_dict[f"级末温度_{i+1}"] = self.stage.data[i, 1]
            default_dict[f"级内等效流量_{i+1}"] = self.stage.data[i, 3]
            default_dict[f"级末比焓_{i+1}"] = self.stage.data[i, 2]
            default_dict[f"级末理想比焓_{i+1}"] = self.stage.data[i, 4]
            default_dict[f"级段效率_{i+1}"] = self.stage.EffStage[i]

        for i in range(0, len(self.reheat.reheater_list)):

            default_dict[f"加热器位置_{i+1}"] = self.reheat.reheater_list[i].pos
            default_dict[f"抽汽压力_{i+1}"] = self.reheat.reheater_list[i].extraction[0]
            default_dict[f"抽汽温度_{i+1}"] = self.reheat.reheater_list[i].extraction[1]
            default_dict[f"抽汽流量_{i+1}"] = self.reheat.reheater_list[i].extraction[3]
            default_dict[f"抽汽比焓_{i+1}"] = self.reheat.reheater_list[i].extraction[2]

            default_dict[f"进口温度_{i+1}"] = self.reheat.reheater_list[i].inlet[1]
            default_dict[f"进口流量_{i+1}"] = self.reheat.reheater_list[i].inlet[3]
            default_dict[f"进口比焓_{i+1}"] = self.reheat.reheater_list[i].inlet[2]

            default_dict[f"出口温度_{i+1}"] = self.reheat.reheater_list[i].outlet[1]
            default_dict[f"出口流量_{i+1}"] = self.reheat.reheater_list[i].outlet[3]
            default_dict[f"出口比焓_{i+1}"] = self.reheat.reheater_list[i].outlet[2]

            default_dict[f"疏水温度_{i+1}"] = self.reheat.reheater_list[i].trap[1]
            default_dict[f"疏水流量_{i+1}"] = self.reheat.reheater_list[i].trap[3]
            default_dict[f"疏水比焓_{i+1}"] = self.reheat.reheater_list[i].trap[2]


        for i in range(2):
            default_dict[f"供热抽汽压力_{i+1}"] = self.suheat.data[i, 0]
            default_dict[f"供热抽汽温度_{i+1}"] = self.suheat.data[i, 1]
            default_dict[f"供热抽汽流量_{i+1}"] = self.suheat.data[i, 3]
            default_dict[f"供热抽汽比焓_{i+1}"] = self.suheat.data[i, 2]
            default_dict[f"供热抽汽位置_{i+1}"] = self.suheat.data[i, 4]

        for i in range(5):
            default_dict[f"补水压力_{i+1}"] = self.suwater.data[i, 0]
            default_dict[f"补水温度_{i+1}"] = self.suwater.data[i, 1]
            default_dict[f"补水流量_{i+1}"] = self.suwater.data[i, 3]
            default_dict[f"补水比焓_{i+1}"] = self.suwater.data[i, 2]
            default_dict[f"补水位置_{i+1}"] = self.suwater.data[i, 4]
        
        for key in default_dict:
            if default_dict[key] == -1:
                print(key)
            
        self.sql.update_data(default_dict, 1)

class ReHeater:
    def __init__(self, _type):
        self.type = _type
        self.pos = -1
        self.extraction = -np.ones(4)
        self.inlet = -np.ones(4)
        self.outlet = -np.ones(4)
        self.trap = -np.ones(4)
        self.trap_ = -np.ones(4)
        self.diff = np.zeros((2, 4))
        self.eff = 1
        self.verbose = VERBOSE
        self.init = False
        
    def calculate_h(self):
        # self.extraction由外部设定
        def calculate(x):
            if x[0] == -1 or x[1] == -1:
                x[2] = PropsSI("H", "T", x[1], "Q", 0, "Water")
            else:
                x[2] = PropsSI("H", "P", x[0], "T", x[1], "Water")
        
        calculate(self.inlet)
        calculate(self.outlet)
        calculate(self.trap)
        calculate(self.trap_)
        calculate(self.diff[0])
        calculate(self.diff[1])
#         self.print_info()
        
        
    def reset_flow(self):
        if self.trap[1] == -1:
            self.trap[3] = 0
        if self.trap_[1] == -1:
            self.trap_[3] =0
        for i in range(self.diff.shape[0]):
            if self.diff[i, 3] == -1:
                self.diff[i, 3] = 0

    def solve_heater(self):
        if self.type == 0:
            self.inlet[3] = self.outlet[3]
            x = Symbol('x')  # 抽汽流量
            y = Symbol('y')  # 疏水流量
            res = solve(
            [
                x + self.trap_[3] + self.diff[0, 3] + self.diff[1, 3] - y,
                self.eff * (self.extraction[2] * x + self.diff[0, 2] * self.diff[0, 3] + self.diff[1, 2] * self.diff[1, 3] + self.trap_[2] * self.trap_[3]  - y * self.trap[2]) - (
                self.outlet[2] * self.outlet[3] - self.inlet[2] * self.inlet[3])
            ], [x, y]
            )
            self.extraction[3] = res[x]
            self.trap[3] = res[y]
            if self.verbose:
                print("抽汽流量：", res[x])
                print("疏水流量：", res[y])
                self.print_info()
        elif self.type == 1:
            x = Symbol('x')  # 抽汽流量
            y = Symbol('y')  # 进口流量
            res = solve(
            [
                x + y + self.trap_[3] + self.diff[0, 3] + self.diff[1, 3] - self.outlet[3],
                self.extraction[2] * x + self.inlet[2] * y + self.trap_[2] * self.trap_[3] + self.diff[0, 2] * self.diff[0, 3] + self.diff[1, 2] * self.diff[1, 3] - self.outlet[2] * self.outlet[3]
            ], [x, y]
            )

            self.extraction[3] = res[x]
            self.inlet[3] = res[y]
            if self.verbose:
                self.print_info()
                print("抽汽流量：", res[x])
                print("进口流量：", res[y])
        else:
            x = Symbol('x')  # 抽汽流量
            y = Symbol('y')  # 疏水流量
            res = solve(
            [
                x + self.trap_[3] - y,
                y + self.inlet[3] - self.outlet[3]
            ], [x, y])
            self.extraction[3] = res[x]
            self.trap[3] = res[y]
            if self.verbose:
                print("抽汽流量：", res[x])
                print("疏水流量：", res[y])
                self.print_info()

    def solve(self):
        if not self.init:
            self.calculate_h()
            self.reset_flow()
            self.init = True
        self.solve_heater()


        
        
    def print_info(self):
        print("抽汽")
        print(f'{self.extraction[0]/1000000}   {self.extraction[1]-273.15} \n{self.extraction[2]/1000}   {self.extraction[3]}')
        print("进口")
        print(f'{self.inlet[0]/1000000}   {self.inlet[1]-273.15} \n{self.inlet[2]/1000}   {self.inlet[3]}')
        print("出口")
        print(f'{self.outlet[0]/1000000}   {self.outlet[1]-273.15} \n{self.outlet[2]/1000}   {self.outlet[3]}')
        print("疏水")
        print(f'{self.trap[0]/1000000}   {self.trap[1]-273.15} \n{self.trap[2]/1000}   {self.trap[3]}')
        print("下级疏水")
        print(f'{self.trap_[0]/1000000}   {self.trap_[1]-273.15} \n{self.trap_[2]/1000}   {self.trap_[3]}')
        print("补水")
        
class ReHeat:
    def __init__(self, turbine):
        self.isDeaecrator = 1
        self.high = 3
        self.low = 3
        self.reheater_list = []
        self.turbine = turbine
        self.create()
        
        
    def set_parameter(self, isDeaecrator, high, low):
        self.isDeaecrator = isDeaecrator
        self.high = high
        self.low = low
        self.create()
        
    def create(self):
        self.reheater_list = []
        for i in range(int(self.high)):
            self.reheater_list.append(ReHeater(0))  
        if self.isDeaecrator == 1:
            self.reheater_list.append(ReHeater(1))
        if int(self.low) > 1:
            for i in range(int(self.low) - 1):
                self.reheater_list.append(ReHeater(0))
        self.reheater_list.append(ReHeater(2))
        # build connection
        for i in range(len(self.reheater_list)):
            if i == 0:
                self.reheater_list[i].outlet = self.turbine.feed
            if i < len(self.reheater_list) - 1:
                self.reheater_list[i].inlet = self.reheater_list[i+1].outlet
            if i != 0:
                self.reheater_list[i].trap_ = self.reheater_list[i-1].trap
            if i == len(self.reheater_list) - 1:
                self.reheater_list[i].inlet = self.turbine.exhaust
            
    def set_diff(self):
        data = self.turbine.suwater.data
        tmp = np.zeros((len(self.reheater_list)))
        for i in range(data.shape[0]):
            pos = data[i, -1]
            for j in range(len(self.reheater_list)):
                if pos == self.reheater_list[j].pos:
                    self.reheater_list[j].diff[int(tmp[j])] = data[i, :-1]
                    tmp[j] += 1
                    break
            
    def get_diff(self):
        curr = 0
        for i in range(len(self.reheater_list)):
            diff = self.reheater_list[i].diff
            for j in range(diff.shape[0]):
                if diff[j, 0] != 0 or diff[j, 1] != 0:
                    self.turbine.suwater.data[curr, :4] = diff[j]
                    curr += 1
                    print(diff[j])

if __name__ == '__main__':
    turbine = Turbine()
    turbine.init_data()
    turbine.stage.solve()
    turbine.update_data()
    print(turbine.stage.EffStage)